package net.cyue.nest.nestjava.core;

import net.cyue.nest.nestjava.common.annotation.core.Injectable;
import net.cyue.nest.nestjava.common.annotation.core.Module;
import net.cyue.nest.nestjava.common.data.InjectableMetaType;
import net.cyue.nest.nestjava.common.data.MetaType;
import net.cyue.nest.nestjava.common.data.module.ControllerMeaType;
import net.cyue.nest.nestjava.common.data.module.ProviderMetaType;
import net.cyue.nest.nestjava.common.interfaces.INestApplicationContext;
import net.cyue.nest.nestjava.core.injector.Injector;
import net.cyue.nest.nestjava.core.injector.MetaTypeFactory;
import net.cyue.nest.nestjava.core.injector.ModuleData;
import net.cyue.nest.nestjava.core.injector.NestContainer;

public class NestApplicationContext
  implements INestApplicationContext
{
  private final NestContainer nestContainer;

  public NestApplicationContext(
    Class<?> appModuleClass,
    NestContainer nestContainer
  ) {
    this.nestContainer = nestContainer;
    this.initContainer(appModuleClass);
  }

  private void initModule(Class<?> moduleClass) {
    Module mA = moduleClass.getAnnotation(Module.class);
    if (mA == null) {
      throw new RuntimeException("提供类型不是模块");
    }
    Class<?>[] importClassArray = mA.imports();
    Class<?>[] providerClassArray = mA.providers();
    Injectable[] injectablesAnnotationArray = mA.injectables();
    Class<?>[] controllerClassArray = mA.controllers();

    MetaType moduleMetaType = MetaTypeFactory.getMetaType(moduleClass);
    ModuleData moduleData = this.nestContainer.addModule(moduleMetaType);
    if (moduleData == null) {
      throw new NullPointerException("初始化错误");
    }

    // module
    for(Class<?> iC : importClassArray) {
      // final var importModule = this.initModule(iC);
      // this.nestContainer.addImport(module, importModule);
      this.initModule(iC);
    }

    // providers
    for(Class<?> pC : providerClassArray) {
      MetaType type = MetaTypeFactory.getMetaType(pC);
      ProviderMetaType providerMetaType = new ProviderMetaType(type);
      this.nestContainer.addProvider(moduleMetaType, providerMetaType);

      Injectable injectableAnnotation = pC.getAnnotation(Injectable.class);
      if (injectableAnnotation != null) {
        String name = Injector.getInjectableName(injectableAnnotation);
        InjectableMetaType injectableMetaType = new InjectableMetaType(type, name);
        this.nestContainer.addInjectable(moduleMetaType, injectableMetaType);
      }
    }

    for (Injectable injectable : injectablesAnnotationArray) {
      String name = Injector.getInjectableName(injectable);
      Class<?> iClz = injectable.useClass();
      InjectableMetaType injectableMetaType = MetaTypeFactory.getInjectableMetaType(iClz, name);
      this.nestContainer.addInjectable(moduleMetaType, injectableMetaType);
    }

    // controllers
    for(Class<?> cC : controllerClassArray) {
      // 创建 Controller
      MetaType ControllerMetaType = MetaTypeFactory.getMetaType(cC);
      ControllerMeaType controllerMeaType = new ControllerMeaType(ControllerMetaType);
      this.nestContainer.addController(moduleMetaType, controllerMeaType);
    }
  }

  private void initContainer(Class<?> appModuleClass) {
    this.initModule(appModuleClass);
  }
  public NestContainer getNestContainer() {
    return this.nestContainer;
  }
}

